//==============================================================================
#include "ListBox.h"

using namespace std;
using namespace ui;

string const ui::ListBox::LISTBOX_TYPE = "LIST_BOX";
//==============================================================================
ListBox::ListBox(int posX, int posY, int width, int height, COMPONENT_TYPE type, string name) : Component(posX, posY, width, height, type, name)
{
}
//------------------------------------------------------------------------------
ListBox::ListBox( int showOpts, int x, int y, int w, int h): Component(x, y, w, h, LISTBOX, "") {
	
	int textHeight = h / showOpts;
	this->opciones = new LISTSTR();
	this->boxes = new VECTBOX();
	this->selectorPrimero.opcionActual = this->opciones->begin();
	this->selectorUltimo.opcionActual = this->opciones->begin();
	this->selectorActual.opcionActual =this->opciones->begin();
	this->cantCajas = showOpts;
	for (int i=0; i<cantCajas; i++)
		this->boxes->push_back (new TextBox(x, y+(i*textHeight), w, textHeight, "", 28));
	(*this->boxes)[0]->setSelected(true);
	this->selectorActual.numCaj = 0;
	this->selectorUltimo.numCaj = 0;
	this->selectorPrimero.numCaj = 0;

}
//------------------------------------------------------------------------------
ListBox::ListBox( int showOpts, int x, int y, int w, int h, LISTSTR* optNames): Component(x, y, w, h, LISTBOX, "") {
	
	this->boxes = new VECTBOX();
	int textHeight = h / showOpts;
	this->opciones = optNames;
	this->cantCajas = showOpts;
	for (int i=0; i<(cantCajas); i++)
		this->boxes->push_back(new TextBox(x, y+(i*textHeight), w, textHeight,"", 28));
	//Fill the textboxes with the first elements of options.
	if (this->opciones->size() >= this->cantCajas) {
		LISTSTR::iterator it = this->opciones->begin();
		for (int i= 0; i<(cantCajas);i++){
			(*this->boxes)[i]->setText(*it);
			it++;
		}
		this->selectorPrimero.opcionActual = this->opciones->begin();
		this->selectorUltimo.opcionActual = this->opciones->begin();
		for (int j=0; j<(cantCajas-1); j++)
			this->selectorUltimo.opcionActual++;
		this->selectorUltimo.numCaj = (cantCajas-1);
		this->selectorActual.opcionActual =this->opciones->begin();
		this->selectorActual.numCaj = 0;
	} else {
		LISTSTR::iterator it = this->opciones->begin();
		for (int i= 0; i < this->opciones->size(); i++){
			(*this->boxes)[i]->setText(*it);
			it++;
		}
		this->selectorUltimo.numCaj=(this->opciones->size()-1);
		this->selectorPrimero.opcionActual = this->opciones->begin();
		it= this->opciones->end();
		it--;
		this->selectorUltimo.opcionActual = it;
		this->selectorActual.opcionActual =this->opciones->begin();
		this->selectorActual.numCaj = 0;
	}
	this->selectorPrimero.numCaj = 0;
	(*this->boxes)[0]->setSelected(true);
}
//------------------------------------------------------------------------------
void ListBox::addOption(string opt){
	if(!opt.empty()) {
		this->opciones->push_back(opt);
		if(this->opciones->size() == 1){
			this->selectorActual.opcionActual = this->opciones->begin();
			this->selectorPrimero.opcionActual = this->opciones->begin();
			this->selectorUltimo.opcionActual = this->opciones->begin();
		}
	//If not empty nor full , update last selector.
		if(this->opciones->size() <= (this->cantCajas) && this->opciones->size()>1 ) {
			this->selectorUltimo.opcionActual++;
			this->selectorUltimo.numCaj++;
		}
		(*this->boxes)[this->selectorUltimo.numCaj]->setText(*this->selectorUltimo.opcionActual);
		//Scroll to show newly added option
		int increment = this->opciones->size() - this->cantCajas;
		for (int i=0;i<increment;i++){
			this->scrollDown();
		}
	}
}
//------------------------------------------------------------------------------
string  ListBox::deleteOption(){
	std::string borrado = "";
	if(!this->opciones->empty())
		borrado = *this->selectorActual.opcionActual;
	if (this->opciones->size() > 1){
		//Delete first box
		if (this->selectorActual.opcionActual == this->opciones->begin()){
			this->selectorPrimero.opcionActual++;
			this->selectorActual.opcionActual++;
			for (int f=0;f<(cantCajas-1);f++)
				(*this->boxes)[f]->setText((*this->boxes)[f+1]->getText());
			this->opciones->pop_front();
			if(this->opciones->size() >= this->cantCajas)
				this->selectorUltimo.opcionActual++;
			else{
				(*this->boxes)[this->selectorUltimo.numCaj]->clearBox();
				this->selectorUltimo.numCaj--;
			}
		}else{
			//Delete intermediate boxes
			LISTSTR::iterator erase = this->selectorActual.opcionActual;
			if (this->selectorActual.opcionActual != this->selectorUltimo.opcionActual){
				this->selectorActual.opcionActual++;
				LISTSTR::iterator end = this->opciones->end();
				end--;
				if(this->selectorUltimo.opcionActual != end)
					this->selectorUltimo.opcionActual++;
				else {
					this->scrollUp();
					if(this->opciones->size() <= this->cantCajas  ){
					(*this->boxes)[this->selectorUltimo.numCaj]->clearBox();
					this->selectorUltimo.numCaj--;
					}else
						this->selectorUltimo.opcionActual++;
				}
				this->opciones->erase(erase);
			} else {
			//Delete last box with option.
				if(this->opciones->size() > this->cantCajas){
					LISTSTR::iterator end = this->opciones->end();
					end--;
					if(this->selectorActual.opcionActual != end){
						this->selectorUltimo.opcionActual++;
						this->selectorActual.opcionActual++;
					}else{
						this->scrollUp();
					}
				} else {
					this->selectorUltimo.opcionActual--;
					this->selectorActual.opcionActual--;
					(*this->boxes)[this->selectorUltimo.numCaj]->clearBox();
					(*this->boxes)[this->selectorActual.numCaj]->setSelected(false);
					this->selectorUltimo.numCaj--;
					this->selectorActual.numCaj--;
					(*this->boxes)[this->selectorActual.numCaj]->setSelected(true);

				}
				this->opciones->erase(erase);
			}
		}
	}else{
		if (!this->opciones->empty()){
			this->opciones->pop_front();
			(*this->boxes)[this->selectorUltimo.numCaj]->clearBox();
			this->selectorActual.opcionActual = this->opciones->begin();
			this->selectorPrimero.opcionActual = this->opciones->begin();
			this->selectorUltimo.opcionActual = this->opciones->begin();
		}
	}
	this->updateBoxes();
	return borrado;
}
//------------------------------------------------------------------------------
string ListBox::getSelected(){
	std::string selected = "";
	if(!this->opciones->empty())
		selected = *this->selectorActual.opcionActual;
	return selected;
}
//------------------------------------------------------------------------------
COMPONENT_TYPE ListBox::handleEvent(SDL_Event* event){
	Uint8* teclas;
	std::list<std::string>::iterator end(this->opciones->end());
	if (!this->opciones->empty()){
	--end;
	};
	teclas = SDL_GetKeyState(NULL);
	if (teclas[SDLK_UP]) {
		if(this->selectorActual.opcionActual !=this->opciones->begin()){
			if(this->selectorActual.opcionActual != this->selectorPrimero.opcionActual){
				(*this->boxes)[this->selectorActual.numCaj]->setSelected(false);
				this->selectorActual.opcionActual--;
				this->selectorActual.numCaj--;
				(*this->boxes)[this->selectorActual.numCaj]->setSelected(true);
			} else {
				//Cambiar lista
				for (int f=(cantCajas-1);f>0;f--)
					(*this->boxes)[f]->setText((*this->boxes)[f-1]->getText());
				this->selectorPrimero.opcionActual--;
				this->selectorUltimo.opcionActual--;
				this->selectorActual.opcionActual--;
				(*this->boxes)[this->selectorActual.numCaj]->setText(*this->selectorActual.opcionActual);
			}
		}

	}
	if (teclas[SDLK_DOWN]) {
		if(this->selectorActual.opcionActual != end) {
			if(this->selectorActual.opcionActual != this->selectorUltimo.opcionActual){
				(*this->boxes)[this->selectorActual.numCaj]->setSelected(false);
				this->selectorActual.opcionActual++;
				this->selectorActual.numCaj++;
				(*this->boxes)[this->selectorActual.numCaj]->setSelected(true);
			}else{
				//Cambiar lista
				for (int f=0;f<(cantCajas-1);f++)
					(*this->boxes)[f]->setText((*this->boxes)[f+1]->getText());
				this->selectorPrimero.opcionActual++;
				this->selectorUltimo.opcionActual++;
				this->selectorActual.opcionActual++;
				(*this->boxes)[this->selectorActual.numCaj]->setText(*this->selectorActual.opcionActual);
			}
		}
	}
	if(event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT){
		for(int i=0;i<this->cantCajas;i++){
			if((*this->boxes)[i]->isClicked(event) && (*this->boxes)[i]->getText().length() > 0 && i != this->selectorActual.numCaj){
				int cajSelec = this->selectorActual.numCaj;
				this->selectorActual.numCaj = i;
				(*this->boxes)[cajSelec]->setSelected(false);
				(*this->boxes)[i]->setSelected(true);
				int diff = i - cajSelec;
				if (diff > 0){
					for (int j =0 ;j < diff;j++)
						this->selectorActual.opcionActual++;
				} else {
					diff = diff* -1;
					for (int j =0 ;j<diff;j++)
						this->selectorActual.opcionActual--;
				}
			}
		}
	}
	return this->type;
}
//------------------------------------------------------------------------------
void ListBox::draw(SDL_Surface* s) throw (SDL_Exception)
{

    try
    {
        if(!this->opciones->empty()){
            (*this->boxes)[this->selectorPrimero.numCaj]->setText(*this->selectorPrimero.opcionActual);
            (*this->boxes)[this->selectorActual.numCaj]->setText(*this->selectorActual.opcionActual);
            (*this->boxes)[this->selectorUltimo.numCaj]->setText(*this->selectorUltimo.opcionActual);
        }
        for (int i=0; i<cantCajas; i++){
            (*this->boxes)[i]->drawBox(s); // draw the box
            (*this->boxes)[i]->drawText(s);
        }
    }
    catch( SDL_Exception &ex)
    {
        throw ex;
    }

}
//------------------------------------------------------------------------------
void ListBox::scrollUp(){
	if ((this->opciones->size()>cantCajas) && (this->selectorPrimero.opcionActual != this->opciones->begin())) {
		for (int f=(cantCajas-1);f>0;f--)
			(*this->boxes)[f]->setText((*this->boxes)[f-1]->getText());
		this->selectorPrimero.opcionActual--;
		this->selectorUltimo.opcionActual--;
		if (this->selectorActual.numCaj != (cantCajas-1)){
			(*this->boxes)[this->selectorActual.numCaj]->setSelected(false);
			this->selectorActual.numCaj++;
			(*this->boxes)[this->selectorActual.numCaj]->setSelected(true);
		} else {
			this->selectorActual.opcionActual--;
		}
		(*this->boxes)[0]->setText(*this->selectorPrimero.opcionActual);
	}

}
//------------------------------------------------------------------------------
void ListBox::scrollDown(){
	list<string>::iterator end(this->opciones->end());
	if(!this->opciones->empty())
		--end;
	//Verify if theres something to scroll on.
	if ((this->opciones->size()>cantCajas) && (this->selectorUltimo.opcionActual != end)) {

		for (int f=0;f<(cantCajas-1);f++)
			(*this->boxes)[f]->setText((*this->boxes)[f+1]->getText());
		this->selectorPrimero.opcionActual++;
		this->selectorUltimo.opcionActual++;
		if (this->selectorActual.numCaj != 0){
			(*this->boxes)[this->selectorActual.numCaj]->setSelected(false);
			this->selectorActual.numCaj--;
			(*this->boxes)[this->selectorActual.numCaj]->setSelected(true);
		} else {
			this->selectorActual.opcionActual++;
		}

		(*this->boxes)[cantCajas-1]->setText(*this->selectorUltimo.opcionActual);
	}
}
//------------------------------------------------------------------------------
ListBox::~ListBox(void) {
	while(!this->opciones->empty()) { 
		this->opciones->pop_back();
	};
	delete this->opciones;

	while(!this->boxes->empty()){ 
		delete this->boxes->back(); 
		this->boxes->pop_back();
	};
	delete this->boxes;


}
//------------------------------------------------------------------------------
string ListBox::getType(void){
	return LISTBOX_TYPE;
}
//------------------------------------------------------------------------------
bool ListBox::findScene(std::string s){
	bool result = false;
	LISTSTR::iterator it = this->opciones->begin();
	while(it !=this->opciones->end() && result != true) {
		if(it->compare(s) == 0)
			result = true;
		it++;
	}
	return result;

}
//------------------------------------------------------------------------------
void ListBox::updateBoxes(){
	LISTSTR::iterator it = this->selectorUltimo.opcionActual;
	int num = this->selectorUltimo.numCaj;
	if(it!= this->selectorPrimero.opcionActual){
		it--;
		num--;
		while(it != this->selectorPrimero.opcionActual){
			(*this->boxes)[num]->setText(*it);
			it--;
			num--;
		}
	}
}
//------------------------------------------------------------------------------
bool ListBox::isEmpty()
{
    return this->opciones->empty();
}
//==============================================================================